Tizen 2.1 release
[platform/core/uifw/e17.git] / src / bin / e_fm_op_registry.c
1 #include "e.h"
2
3 EAPI int E_EVENT_FM_OP_REGISTRY_ADD = 0;
4 EAPI int E_EVENT_FM_OP_REGISTRY_DEL = 0;
5 EAPI int E_EVENT_FM_OP_REGISTRY_CHANGED = 0;
6
7 static Eina_Hash *_e_fm2_op_registry = NULL;
8 static unsigned int _e_fm2_init_count = 0;
9
10 typedef struct _E_Fm2_Op_Registry_Entry_Listener E_Fm2_Op_Registry_Entry_Listener;
11 typedef struct _E_Fm2_Op_Registry_Entry_Internal E_Fm2_Op_Registry_Entry_Internal;
12
13 struct _E_Fm2_Op_Registry_Entry_Listener
14 {
15    EINA_INLIST;
16    void  (*cb)(void *data, const E_Fm2_Op_Registry_Entry *entry);
17    void *data;
18    void  (*free_data)(void *data);
19 };
20
21 struct _E_Fm2_Op_Registry_Entry_Internal
22 {
23    E_Fm2_Op_Registry_Entry entry;
24    Eina_Inlist            *listeners;
25    int                     references;
26    Ecore_Event            *changed_event;
27 };
28
29 static void
30 _e_fm2_op_registry_entry_e_fm_deleted(void *data, Evas *evas __UNUSED__, Evas_Object *e_fm __UNUSED__, void *event __UNUSED__)
31 {
32    E_Fm2_Op_Registry_Entry *entry = data;
33
34    entry->e_fm = NULL;
35    e_fm2_op_registry_entry_changed(entry);
36 }
37
38 static void
39 _e_fm2_op_registry_entry_e_fm_monitor_start(const E_Fm2_Op_Registry_Entry *entry)
40 {
41    if (!entry->e_fm) return;
42    evas_object_event_callback_add
43      (entry->e_fm, EVAS_CALLBACK_DEL,
44      _e_fm2_op_registry_entry_e_fm_deleted, entry);
45 }
46
47 static void
48 _e_fm2_op_registry_entry_e_fm_monitor_stop(const E_Fm2_Op_Registry_Entry *entry)
49 {
50    if (!entry->e_fm) return;
51    evas_object_event_callback_del_full
52      (entry->e_fm, EVAS_CALLBACK_DEL,
53      _e_fm2_op_registry_entry_e_fm_deleted, entry);
54 }
55
56 static inline E_Fm2_Op_Registry_Entry_Internal *
57 _e_fm2_op_registry_entry_internal_get(const E_Fm2_Op_Registry_Entry *entry)
58 {
59    return (E_Fm2_Op_Registry_Entry_Internal *)entry;
60 }
61
62 static void
63 _e_fm2_op_registry_entry_internal_free(E_Fm2_Op_Registry_Entry_Internal *e)
64 {
65    _e_fm2_op_registry_entry_e_fm_monitor_stop(&(e->entry));
66
67    while (e->listeners)
68      {
69         E_Fm2_Op_Registry_Entry_Listener *listener = (void *)e->listeners;
70         e->listeners = eina_inlist_remove(e->listeners, e->listeners);
71
72         if (listener->free_data) listener->free_data(listener->data);
73         free(listener);
74      }
75
76    eina_stringshare_del(e->entry.src);
77    eina_stringshare_del(e->entry.dst);
78    free(e);
79 }
80
81 static inline int
82 _e_fm2_op_registry_entry_internal_unref(E_Fm2_Op_Registry_Entry_Internal *e)
83 {
84    if (e->references < 1)
85      return 0;
86
87    e->references--;
88    if (e->references > 0)
89      return e->references;
90
91    _e_fm2_op_registry_entry_internal_free(e);
92    return 0;
93 }
94
95 static inline int
96 _e_fm2_op_registry_entry_internal_ref(E_Fm2_Op_Registry_Entry_Internal *e)
97 {
98    e->references++;
99    return e->references;
100 }
101
102 static void
103 _e_fm2_op_registry_entry_listeners_call(const E_Fm2_Op_Registry_Entry_Internal *e)
104 {
105    E_Fm2_Op_Registry_Entry_Listener *listener;
106    Eina_Inlist *l;
107
108    if (eina_inlist_count(e->listeners) < 1) return;
109
110    EINA_INLIST_FOREACH_SAFE (e->listeners, l, listener)
111      listener->cb(listener->data, &e->entry);
112 }
113
114 static void
115 _e_fm2_op_registry_entry_internal_unref_on_event(void *data, void *event __UNUSED__)
116 {
117    E_Fm2_Op_Registry_Entry_Internal *e = data;
118    _e_fm2_op_registry_entry_internal_unref(e);
119 }
120
121 static void
122 _e_fm2_op_registry_entry_internal_event(E_Fm2_Op_Registry_Entry_Internal *e, int event_type)
123 {
124    _e_fm2_op_registry_entry_internal_ref(e);
125    ecore_event_add(event_type, &(e->entry),
126                    _e_fm2_op_registry_entry_internal_unref_on_event, e);
127 }
128
129 Eina_Bool
130 e_fm2_op_registry_entry_add(int id, Evas_Object *e_fm, E_Fm_Op_Type op, E_Fm2_Op_Registry_Abort_Func abrt)
131 {
132    E_Fm2_Op_Registry_Entry_Internal *e;
133
134    e = E_NEW(E_Fm2_Op_Registry_Entry_Internal, 1);
135    if (!e) return 0;
136
137    e->entry.id = id;
138    e->entry.e_fm = e_fm;
139    e->entry.start_time = ecore_loop_time_get();
140    e->entry.op = op;
141    e->entry.status = E_FM2_OP_STATUS_IN_PROGRESS;
142    e->entry.func.abort = abrt;
143    e->references = 1;
144
145    if (!eina_hash_add(_e_fm2_op_registry, &id, e))
146      {
147         free(e);
148         return 0;
149      }
150
151    _e_fm2_op_registry_entry_e_fm_monitor_start(&(e->entry));
152    _e_fm2_op_registry_entry_internal_event(e, E_EVENT_FM_OP_REGISTRY_ADD);
153
154    return 1;
155 }
156
157 Eina_Bool
158 e_fm2_op_registry_entry_del(int id)
159 {
160    E_Fm2_Op_Registry_Entry_Internal *e;
161
162    e = eina_hash_find(_e_fm2_op_registry, &id);
163    if (!e) return 0;
164    eina_hash_del_by_key(_e_fm2_op_registry, &id);
165
166    _e_fm2_op_registry_entry_internal_event(e, E_EVENT_FM_OP_REGISTRY_DEL);
167    _e_fm2_op_registry_entry_internal_unref(e);
168
169    return 1;
170 }
171
172 static void
173 _e_fm2_op_registry_entry_internal_unref_on_changed_event(void *data, void *event __UNUSED__)
174 {
175    E_Fm2_Op_Registry_Entry_Internal *e = data;
176    e->changed_event = NULL;
177    _e_fm2_op_registry_entry_internal_unref(e);
178 }
179
180 void
181 e_fm2_op_registry_entry_changed(const E_Fm2_Op_Registry_Entry *entry)
182 {
183    E_Fm2_Op_Registry_Entry_Internal *e;
184
185    if (!entry) return;
186    e = _e_fm2_op_registry_entry_internal_get(entry);
187
188    _e_fm2_op_registry_entry_listeners_call(e);
189
190    if (e->changed_event) return;
191    _e_fm2_op_registry_entry_internal_ref(e);
192    e->changed_event = ecore_event_add
193        (E_EVENT_FM_OP_REGISTRY_CHANGED, &(e->entry),
194        _e_fm2_op_registry_entry_internal_unref_on_changed_event, e);
195 }
196
197 /**
198  * Set the new e_fm for this operation.
199  *
200  * Use this call instead of directly setting in order to have the
201  * object to be monitored, when it is gone, the pointer will be made
202  * NULL.
203  *
204  * @note: it will not call any listener or add any event, please use
205  * e_fm2_op_registry_entry_changed().
206  */
207 void
208 e_fm2_op_registry_entry_e_fm_set(E_Fm2_Op_Registry_Entry *entry, Evas_Object *e_fm)
209 {
210    if (!entry) return;
211    _e_fm2_op_registry_entry_e_fm_monitor_stop(entry);
212    entry->e_fm = e_fm;
213    _e_fm2_op_registry_entry_e_fm_monitor_start(entry);
214 }
215
216 /**
217  * Set the new files for this operation.
218  *
219  * Use this call instead of directly setting in order to have
220  * stringshare references right.
221  *
222  * @note: it will not call any listener or add any event, please use
223  * e_fm2_op_registry_entry_changed().
224  */
225 void
226 e_fm2_op_registry_entry_files_set(E_Fm2_Op_Registry_Entry *entry, const char *src, const char *dst)
227 {
228    if (!entry) return;
229
230    eina_stringshare_replace(&entry->src, src);
231    eina_stringshare_replace(&entry->dst, dst);
232 }
233
234 /**
235  * Adds a reference to given entry.
236  *
237  * @return: new number of references after operation or -1 on error.
238  */
239 EAPI int
240 e_fm2_op_registry_entry_ref(E_Fm2_Op_Registry_Entry *entry)
241 {
242    E_Fm2_Op_Registry_Entry_Internal *e;
243
244    if (!entry) return -1;
245
246    e = _e_fm2_op_registry_entry_internal_get(entry);
247    return _e_fm2_op_registry_entry_internal_ref(e);
248 }
249
250 /**
251  * Releases a reference to given entry.
252  *
253  * @return: new number of references after operation or -1 on error,
254  *    if 0 the entry was freed and pointer is then invalid.
255  */
256 EAPI int
257 e_fm2_op_registry_entry_unref(E_Fm2_Op_Registry_Entry *entry)
258 {
259    E_Fm2_Op_Registry_Entry_Internal *e;
260
261    if (!entry) return -1;
262
263    e = _e_fm2_op_registry_entry_internal_get(entry);
264    return _e_fm2_op_registry_entry_internal_unref(e);
265 }
266
267 /**
268  * Returns the X window associated to this operation.
269  *
270  * This will handle all bureaucracy to get X window based on e_fm evas
271  * object.
272  *
273  * @return: 0 if no window, window identifier otherwise.
274  */
275 EAPI Ecore_X_Window
276 e_fm2_op_registry_entry_xwin_get(const E_Fm2_Op_Registry_Entry *entry)
277 {
278    Evas *e;
279    Ecore_Evas *ee;
280
281    if (!entry) return 0;
282    if (!entry->e_fm) return 0;
283
284    e = evas_object_evas_get(entry->e_fm);
285    if (!e) return 0;
286
287    ee = evas_data_attach_get(e);
288    if (!ee) return 0;
289
290    return (Ecore_X_Window)(long)ecore_evas_window_get(ee);
291 }
292
293 /**
294  * Discover entry based on its identifier.
295  *
296  * @note: does not increment reference.
297  */
298 EAPI E_Fm2_Op_Registry_Entry *
299 e_fm2_op_registry_entry_get(int id)
300 {
301    return eina_hash_find(_e_fm2_op_registry, &id);
302 }
303
304 /**
305  * Adds a function to be called when entry changes.
306  *
307  * When entry changes any attribute this function will be called.
308  *
309  * @param: entry entry to operate on.
310  * @param: cb function to callback on changes.
311  * @param: data extra data to give to @p cb
312  * @param: free_data function to call when listener is removed, entry
313  *    is deleted or any error occur in this function and listener
314  *    cannot be added.
315  *
316  * @note: does not increment reference.
317  * @note: on errors, @p free_data will be called.
318  */
319 EAPI void
320 e_fm2_op_registry_entry_listener_add(E_Fm2_Op_Registry_Entry *entry, void (*cb)(void *data, const E_Fm2_Op_Registry_Entry *entry), const void *data, void (*free_data)(void *data))
321 {
322    E_Fm2_Op_Registry_Entry_Internal *e;
323    E_Fm2_Op_Registry_Entry_Listener *listener;
324    Eina_Error err;
325
326    if ((!entry) || (!cb))
327      {
328         if (free_data) free_data((void *)data);
329         return;
330      }
331
332    listener = malloc(sizeof(*listener));
333    if (!listener)
334      {
335         if (free_data) free_data((void *)data);
336         return;
337      }
338    listener->cb = cb;
339    listener->data = (void *)data;
340    listener->free_data = free_data;
341
342    e = _e_fm2_op_registry_entry_internal_get(entry);
343    e->listeners = eina_inlist_append(e->listeners, EINA_INLIST_GET(listener));
344    err = eina_error_get();
345    if (err)
346      {
347         printf("could not add listener: %s\n", eina_error_msg_get(err));
348         if (free_data) free_data((void *)data);
349         free(listener);
350         return;
351      }
352 }
353
354 /**
355  * Removes the function to be called when entry changes.
356  *
357  * @param: entry entry to operate on.
358  * @param: cb function to callback on changes.
359  * @param: data extra data to give to @p cb
360  *
361  * @note: does not decrement reference.
362  * @see: e_fm2_op_registry_entry_listener_add()
363  */
364 EAPI void
365 e_fm2_op_registry_entry_listener_del(E_Fm2_Op_Registry_Entry *entry, void (*cb)(void *data, const E_Fm2_Op_Registry_Entry *entry), const void *data)
366 {
367    E_Fm2_Op_Registry_Entry_Internal *e;
368    E_Fm2_Op_Registry_Entry_Listener *l;
369
370    if ((!entry) || (!cb)) return;
371    e = _e_fm2_op_registry_entry_internal_get(entry);
372
373    EINA_INLIST_FOREACH(e->listeners, l)
374      if ((l->cb == cb) && (l->data == data))
375        {
376           e->listeners = eina_inlist_remove(e->listeners, EINA_INLIST_GET(l));
377           if (l->free_data) l->free_data(l->data);
378           free(l);
379           return;
380        }
381 }
382
383 /**
384  * Returns an iterator over all the entries in the fm operations registry.
385  *
386  * @warning: this iterator is just valid until new entries are added
387  *    or removed (usually happens from main loop). This is because
388  *    when system is back to main loop it can report new events and
389  *    operations can be added or removed from this registry. In other
390  *    words, it is fine to call this function, immediately walk the
391  *    iterator and do something, then free the iterator. You can use
392  *    it to create a shadow list if you wish.
393  *
394  * @see e_fm2_op_registry_get_all()
395  */
396 EAPI Eina_Iterator *
397 e_fm2_op_registry_iterator_new(void)
398 {
399    return eina_hash_iterator_data_new(_e_fm2_op_registry);
400 }
401
402 /**
403  * Returns a shadow list with all entries in the registry.
404  *
405  * All entries will have references incremented, so you must free the
406  * list with e_fm2_op_registry_get_all_free() to free the list and
407  * release these references.
408  *
409  * @note: List is unsorted!
410  * @note: if you need a simple, immediate walk, use
411  *    e_fm2_op_registry_iterator_new()
412  */
413 EAPI Eina_List *
414 e_fm2_op_registry_get_all(void)
415 {
416    Eina_List *list;
417    Eina_Iterator *it;
418    E_Fm2_Op_Registry_Entry_Internal *e;
419
420    list = NULL;
421    it = eina_hash_iterator_data_new(_e_fm2_op_registry);
422    EINA_ITERATOR_FOREACH(it, e)
423      {
424         _e_fm2_op_registry_entry_internal_ref(e);
425         list = eina_list_append(list, &(e->entry));
426      }
427    eina_iterator_free(it);
428
429    return list;
430 }
431
432 EAPI void
433 e_fm2_op_registry_get_all_free(Eina_List *list)
434 {
435    E_Fm2_Op_Registry_Entry *entry;
436    EINA_LIST_FREE(list, entry)
437      e_fm2_op_registry_entry_unref(entry);
438 }
439
440 EAPI Eina_Bool
441 e_fm2_op_registry_is_empty(void)
442 {
443    return eina_hash_population(_e_fm2_op_registry) == 0;
444 }
445
446 EAPI int
447 e_fm2_op_registry_count(void)
448 {
449    return eina_hash_population(_e_fm2_op_registry);
450 }
451
452 EINTERN unsigned int
453 e_fm2_op_registry_init(void)
454 {
455    _e_fm2_init_count++;
456    if (_e_fm2_init_count > 1) return _e_fm2_init_count;
457
458    _e_fm2_op_registry = eina_hash_int32_new(NULL);
459    if (!_e_fm2_op_registry)
460      {
461         _e_fm2_init_count = 0;
462         return 0;
463      }
464
465    if (E_EVENT_FM_OP_REGISTRY_ADD == 0)
466      E_EVENT_FM_OP_REGISTRY_ADD = ecore_event_type_new();
467    if (E_EVENT_FM_OP_REGISTRY_DEL == 0)
468      E_EVENT_FM_OP_REGISTRY_DEL = ecore_event_type_new();
469    if (E_EVENT_FM_OP_REGISTRY_CHANGED == 0)
470      E_EVENT_FM_OP_REGISTRY_CHANGED = ecore_event_type_new();
471
472    return 1;
473 }
474
475 EINTERN unsigned int
476 e_fm2_op_registry_shutdown(void)
477 {
478    if (_e_fm2_init_count == 0) return 0;
479    _e_fm2_init_count--;
480    if (_e_fm2_init_count > 0) return _e_fm2_init_count;
481
482    eina_hash_free(_e_fm2_op_registry);
483    _e_fm2_op_registry = NULL;
484
485    return 0;
486 }
487
488 EAPI void
489 e_fm2_op_registry_entry_abort(E_Fm2_Op_Registry_Entry *entry)
490 {
491    if (!entry) return;
492
493    if (entry->func.abort)
494      entry->func.abort(entry);
495 }
496