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;
7 static Eina_Hash *_e_fm2_op_registry = NULL;
8 static unsigned int _e_fm2_init_count = 0;
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;
13 struct _E_Fm2_Op_Registry_Entry_Listener
16 void (*cb)(void *data, const E_Fm2_Op_Registry_Entry *entry);
18 void (*free_data)(void *data);
21 struct _E_Fm2_Op_Registry_Entry_Internal
23 E_Fm2_Op_Registry_Entry entry;
24 Eina_Inlist *listeners;
26 Ecore_Event *changed_event;
30 _e_fm2_op_registry_entry_e_fm_deleted(void *data, Evas *evas __UNUSED__, Evas_Object *e_fm __UNUSED__, void *event __UNUSED__)
32 E_Fm2_Op_Registry_Entry *entry = data;
35 e_fm2_op_registry_entry_changed(entry);
39 _e_fm2_op_registry_entry_e_fm_monitor_start(const E_Fm2_Op_Registry_Entry *entry)
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);
48 _e_fm2_op_registry_entry_e_fm_monitor_stop(const E_Fm2_Op_Registry_Entry *entry)
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);
57 static inline E_Fm2_Op_Registry_Entry_Internal *
58 _e_fm2_op_registry_entry_internal_get(const E_Fm2_Op_Registry_Entry *entry)
60 return (E_Fm2_Op_Registry_Entry_Internal *)entry;
64 _e_fm2_op_registry_entry_internal_free(E_Fm2_Op_Registry_Entry_Internal *e)
66 _e_fm2_op_registry_entry_e_fm_monitor_stop(&(e->entry));
70 E_Fm2_Op_Registry_Entry_Listener *listener = (void *)e->listeners;
71 e->listeners = eina_inlist_remove(e->listeners, e->listeners);
73 if (listener->free_data) listener->free_data(listener->data);
77 eina_stringshare_del(e->entry.src);
78 eina_stringshare_del(e->entry.dst);
83 _e_fm2_op_registry_entry_internal_unref(E_Fm2_Op_Registry_Entry_Internal *e)
85 if (e->references < 1)
89 if (e->references > 0)
92 _e_fm2_op_registry_entry_internal_free(e);
97 _e_fm2_op_registry_entry_internal_ref(E_Fm2_Op_Registry_Entry_Internal *e)
100 return e->references;
104 _e_fm2_op_registry_entry_listeners_call(const E_Fm2_Op_Registry_Entry_Internal *e)
106 E_Fm2_Op_Registry_Entry_Listener *l, **shadow;
107 const E_Fm2_Op_Registry_Entry *entry;
108 unsigned int i, count;
110 /* NB: iterate on a copy in order to allow listeners to be deleted
111 * from callbacks. number of listeners should be small, so the
112 * following should do fine.
114 count = eina_inlist_count(e->listeners);
115 if (count < 1) return;
117 shadow = alloca(sizeof(*shadow) * count);
121 EINA_INLIST_FOREACH(e->listeners, l)
125 for (i = 0; i < count; i++)
126 shadow[i]->cb(shadow[i]->data, entry);
130 _e_fm2_op_registry_entry_internal_unref_on_event(void *data, void *event __UNUSED__)
132 E_Fm2_Op_Registry_Entry_Internal *e = data;
133 _e_fm2_op_registry_entry_internal_unref(e);
137 _e_fm2_op_registry_entry_internal_event(E_Fm2_Op_Registry_Entry_Internal *e, int event_type)
139 _e_fm2_op_registry_entry_internal_ref(e);
140 ecore_event_add(event_type, &(e->entry),
141 _e_fm2_op_registry_entry_internal_unref_on_event, e);
145 e_fm2_op_registry_entry_add(int id, Evas_Object *e_fm, E_Fm_Op_Type op, E_Fm2_Op_Registry_Abort_Func abort)
147 E_Fm2_Op_Registry_Entry_Internal *e;
149 e = E_NEW(E_Fm2_Op_Registry_Entry_Internal, 1);
153 e->entry.e_fm = e_fm;
154 e->entry.start_time = ecore_loop_time_get();
156 e->entry.status = E_FM2_OP_STATUS_IN_PROGRESS;
157 e->entry.func.abort = abort;
160 if (!eina_hash_add(_e_fm2_op_registry, &id, e))
166 _e_fm2_op_registry_entry_e_fm_monitor_start(&(e->entry));
167 _e_fm2_op_registry_entry_internal_event(e, E_EVENT_FM_OP_REGISTRY_ADD);
173 e_fm2_op_registry_entry_del(int id)
175 E_Fm2_Op_Registry_Entry_Internal *e;
177 e = eina_hash_find(_e_fm2_op_registry, &id);
179 eina_hash_del_by_key(_e_fm2_op_registry, &id);
181 _e_fm2_op_registry_entry_internal_event(e, E_EVENT_FM_OP_REGISTRY_DEL);
182 _e_fm2_op_registry_entry_internal_unref(e);
188 _e_fm2_op_registry_entry_internal_unref_on_changed_event(void *data, void *event __UNUSED__)
190 E_Fm2_Op_Registry_Entry_Internal *e = data;
191 e->changed_event = NULL;
192 _e_fm2_op_registry_entry_internal_unref(e);
196 e_fm2_op_registry_entry_changed(const E_Fm2_Op_Registry_Entry *entry)
198 E_Fm2_Op_Registry_Entry_Internal *e;
201 e = _e_fm2_op_registry_entry_internal_get(entry);
203 _e_fm2_op_registry_entry_listeners_call(e);
205 if (e->changed_event) return;
206 _e_fm2_op_registry_entry_internal_ref(e);
207 e->changed_event = ecore_event_add
208 (E_EVENT_FM_OP_REGISTRY_CHANGED, &(e->entry),
209 _e_fm2_op_registry_entry_internal_unref_on_changed_event, e);
213 * Set the new e_fm for this operation.
215 * Use this call instead of directly setting in order to have the
216 * object to be monitored, when it is gone, the pointer will be made
219 * @note: it will not call any listener or add any event, please use
220 * e_fm2_op_registry_entry_changed().
223 e_fm2_op_registry_entry_e_fm_set(E_Fm2_Op_Registry_Entry *entry, Evas_Object *e_fm)
226 _e_fm2_op_registry_entry_e_fm_monitor_stop(entry);
228 _e_fm2_op_registry_entry_e_fm_monitor_start(entry);
232 * Set the new files for this operation.
234 * Use this call instead of directly setting in order to have
235 * stringshare references right.
237 * @note: it will not call any listener or add any event, please use
238 * e_fm2_op_registry_entry_changed().
241 e_fm2_op_registry_entry_files_set(E_Fm2_Op_Registry_Entry *entry, const char *src, const char *dst)
245 eina_stringshare_replace(&entry->src, src);
246 eina_stringshare_replace(&entry->dst, dst);
250 * Adds a reference to given entry.
252 * @return: new number of references after operation or -1 on error.
255 e_fm2_op_registry_entry_ref(E_Fm2_Op_Registry_Entry *entry)
257 E_Fm2_Op_Registry_Entry_Internal *e;
259 if (!entry) return -1;
261 e = _e_fm2_op_registry_entry_internal_get(entry);
262 return _e_fm2_op_registry_entry_internal_ref(e);
266 * Releases a reference to given entry.
268 * @return: new number of references after operation or -1 on error,
269 * if 0 the entry was freed and pointer is then invalid.
272 e_fm2_op_registry_entry_unref(E_Fm2_Op_Registry_Entry *entry)
274 E_Fm2_Op_Registry_Entry_Internal *e;
276 if (!entry) return -1;
278 e = _e_fm2_op_registry_entry_internal_get(entry);
279 return _e_fm2_op_registry_entry_internal_unref(e);
283 * Returns the X window associated to this operation.
285 * This will handle all bureaucracy to get X window based on e_fm evas
288 * @return: 0 if no window, window identifier otherwise.
291 e_fm2_op_registry_entry_xwin_get(const E_Fm2_Op_Registry_Entry *entry)
296 if (!entry) return 0;
297 if (!entry->e_fm) return 0;
299 e = evas_object_evas_get(entry->e_fm);
302 ee = evas_data_attach_get(e);
305 return (Ecore_X_Window)(long)ecore_evas_window_get(ee);
309 * Discover entry based on its identifier.
311 * @note: does not increment reference.
313 EAPI E_Fm2_Op_Registry_Entry *
314 e_fm2_op_registry_entry_get(int id)
316 return eina_hash_find(_e_fm2_op_registry, &id);
320 * Adds a function to be called when entry changes.
322 * When entry changes any attribute this function will be called.
324 * @param: entry entry to operate on.
325 * @param: cb function to callback on changes.
326 * @param: data extra data to give to @p cb
327 * @param: free_data function to call when listener is removed, entry
328 * is deleted or any error occur in this function and listener
331 * @note: does not increment reference.
332 * @note: on errors, @p free_data will be called.
335 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))
337 E_Fm2_Op_Registry_Entry_Internal *e;
338 E_Fm2_Op_Registry_Entry_Listener *listener;
341 if ((!entry) || (!cb))
343 if (free_data) free_data((void *)data);
347 listener = malloc(sizeof(*listener));
350 if (free_data) free_data((void *)data);
354 listener->data = (void *)data;
355 listener->free_data = free_data;
357 e = _e_fm2_op_registry_entry_internal_get(entry);
358 e->listeners = eina_inlist_append(e->listeners, EINA_INLIST_GET(listener));
359 err = eina_error_get();
362 printf("could not add listener: %s\n", eina_error_msg_get(err));
363 if (free_data) free_data((void *)data);
370 * Removes the function to be called when entry changes.
372 * @param: entry entry to operate on.
373 * @param: cb function to callback on changes.
374 * @param: data extra data to give to @p cb
376 * @note: does not decrement reference.
377 * @see: e_fm2_op_registry_entry_listener_add()
380 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)
382 E_Fm2_Op_Registry_Entry_Internal *e;
383 E_Fm2_Op_Registry_Entry_Listener *l;
385 if ((!entry) || (!cb)) return;
386 e = _e_fm2_op_registry_entry_internal_get(entry);
388 EINA_INLIST_FOREACH(e->listeners, l)
389 if ((l->cb == cb) && (l->data == data))
391 e->listeners = eina_inlist_remove(e->listeners, EINA_INLIST_GET(l));
392 if (l->free_data) l->free_data(l->data);
399 * Returns an iterator over all the entries in the fm operations registry.
401 * @warning: this iterator is just valid until new entries are added
402 * or removed (usually happens from main loop). This is because
403 * when system is back to main loop it can report new events and
404 * operations can be added or removed from this registry. In other
405 * words, it is fine to call this function, immediately walk the
406 * iterator and do something, then free the iterator. You can use
407 * it to create a shadow list if you wish.
409 * @see e_fm2_op_registry_get_all()
412 e_fm2_op_registry_iterator_new(void)
414 return eina_hash_iterator_data_new(_e_fm2_op_registry);
418 * Returns a shadow list with all entries in the registry.
420 * All entries will have references incremented, so you must free the
421 * list with e_fm2_op_registry_get_all_free() to free the list and
422 * release these references.
424 * @note: List is unsorted!
425 * @note: if you need a simple, immediate walk, use
426 * e_fm2_op_registry_iterator_new()
429 e_fm2_op_registry_get_all(void)
433 E_Fm2_Op_Registry_Entry_Internal *e;
436 it = eina_hash_iterator_data_new(_e_fm2_op_registry);
437 EINA_ITERATOR_FOREACH(it, e)
439 _e_fm2_op_registry_entry_internal_ref(e);
440 list = eina_list_append(list, &(e->entry));
442 eina_iterator_free(it);
448 e_fm2_op_registry_get_all_free(Eina_List *list)
450 E_Fm2_Op_Registry_Entry *entry;
451 EINA_LIST_FREE(list, entry)
452 e_fm2_op_registry_entry_unref(entry);
456 e_fm2_op_registry_is_empty(void)
458 return eina_hash_population(_e_fm2_op_registry) == 0;
462 e_fm2_op_registry_count(void)
464 return eina_hash_population(_e_fm2_op_registry);
469 e_fm2_op_registry_init(void)
472 if (_e_fm2_init_count > 1) return _e_fm2_init_count;
474 _e_fm2_op_registry = eina_hash_int32_new(NULL);
475 if (!_e_fm2_op_registry)
477 _e_fm2_init_count = 0;
481 if (E_EVENT_FM_OP_REGISTRY_ADD == 0)
482 E_EVENT_FM_OP_REGISTRY_ADD = ecore_event_type_new();
483 if (E_EVENT_FM_OP_REGISTRY_DEL == 0)
484 E_EVENT_FM_OP_REGISTRY_DEL = ecore_event_type_new();
485 if (E_EVENT_FM_OP_REGISTRY_CHANGED == 0)
486 E_EVENT_FM_OP_REGISTRY_CHANGED = ecore_event_type_new();
492 e_fm2_op_registry_shutdown(void)
494 if (_e_fm2_init_count == 0) return 0;
496 if (_e_fm2_init_count > 0) return _e_fm2_init_count;
498 eina_hash_free(_e_fm2_op_registry);
499 _e_fm2_op_registry = NULL;
505 e_fm2_op_registry_entry_abort(E_Fm2_Op_Registry_Entry *entry)
509 if (entry->func.abort)
510 entry->func.abort(entry);