diff --git a/src/bin/Makefile.am b/src/bin/Makefile.am index 2e4d3b326..1cf5375f8 100644 --- a/src/bin/Makefile.am +++ b/src/bin/Makefile.am @@ -136,6 +136,7 @@ e_int_border_prop.h \ e_entry_dialog.h \ e_fm.h \ e_fm_op.h \ +e_fm_op_registry.h \ e_fm_hal.h \ e_widget_scrollframe.h \ e_sha1.h \ @@ -276,6 +277,7 @@ e_int_border_prop.c \ e_entry_dialog.c \ e_fm.c \ e_fm_hal.c \ +e_fm_op_registry.c \ e_widget_scrollframe.c \ e_sha1.c \ e_widget_fsel.c \ diff --git a/src/bin/e_fm.c b/src/bin/e_fm.c index c51c1ee67..8d7fc4d84 100644 --- a/src/bin/e_fm.c +++ b/src/bin/e_fm.c @@ -377,13 +377,13 @@ static void _e_fm2_client_spawn(void); static E_Fm2_Client *_e_fm2_client_get(void); static int _e_fm2_client_monitor_add(const char *path); static void _e_fm2_client_monitor_del(int id, const char *path); -static int _e_fm_client_file_del(const char *args); -static int _e_fm2_client_file_trash(const char *path); -static int _e_fm2_client_file_mkdir(const char *path, const char *rel, int rel_to, int x, int y, int res_w, int res_h); -static int _e_fm_client_file_move(const char *args); -static int _e_fm2_client_file_symlink(const char *path, const char *dest, const char *rel, int rel_to, int x, int y, int res_w, int res_h); -static int _e_fm_client_file_copy(const char *args); -static int _e_fm_client_file_symlink(const char *args); +static int _e_fm_client_file_del(const char *args, Evas_Object *e_fm); +static int _e_fm2_client_file_trash(const char *path, Evas_Object *e_fm); +static int _e_fm2_client_file_mkdir(const char *path, const char *rel, int rel_to, int x, int y, int res_w, int res_h, Evas_Object *e_fm); +static int _e_fm_client_file_move(const char *args, Evas_Object *e_fm); +static int _e_fm2_client_file_symlink(const char *path, const char *dest, const char *rel, int rel_to, int x, int y, int res_w, int res_h, Evas_Object *e_fm); +static int _e_fm_client_file_copy(const char *args, Evas_Object *e_fm); +static int _e_fm_client_file_symlink(const char *args, Evas_Object *e_fm); static void _e_fm2_sel_rect_update(void *data); static inline void _e_fm2_context_menu_append(Evas_Object *obj, const char *path, Eina_List *l, E_Menu *mn, E_Fm2_Icon *ic); @@ -555,6 +555,105 @@ _e_fm2_mime_clear_cb(void *data __UNUSED__) return 1; } +static void +_e_fm2_op_registry_go_on(int id) +{ + E_Fm2_Op_Registry_Entry *ere = e_fm2_op_registry_entry_get(id); + if (!ere) return; + ere->status = E_FM2_OP_STATUS_IN_PROGRESS; + ere->needs_attention = 0; + e_fm2_op_registry_entry_changed(ere); +} + +static void +_e_fm2_op_registry_aborted(int id) +{ + E_Fm2_Op_Registry_Entry *ere = e_fm2_op_registry_entry_get(id); + if (!ere) return; + ere->status = E_FM2_OP_STATUS_ABORTED; + ere->needs_attention = 0; + ere->finished = 1; + e_fm2_op_registry_entry_changed(ere); + // XXX e_fm2_op_registry_entry_del(id); +} + +static void +_e_fm2_op_registry_error(int id) +{ + E_Fm2_Op_Registry_Entry *ere = e_fm2_op_registry_entry_get(id); + if (!ere) return; + ere->status = E_FM2_OP_STATUS_ERROR; + ere->needs_attention = 1; + e_fm2_op_registry_entry_changed(ere); +} + +static void +_e_fm2_op_registry_needs_attention(int id) +{ + E_Fm2_Op_Registry_Entry *ere = e_fm2_op_registry_entry_get(id); + if (!ere) return; + ere->needs_attention = 1; + e_fm2_op_registry_entry_changed(ere); +} + +/////////////// DBG: +static void +_e_fm2_op_registry_entry_print(const E_Fm2_Op_Registry_Entry *ere) +{ + const char *status_strings[] = { + "UNKNOWN", "IN_PROGRESS", "SUCCESSFUL", "ABORTED", "ERROR" + }; + const char *status; + + if ((ere->status >= 0) && + (ere->status < sizeof(status_strings)/sizeof(status_strings[0]))) + status = status_strings[ere->status]; + else + status = status_strings[0]; + + printf("id: %8d, op: %2d [%s] finished: %hhu, needs_attention: %hhu\n" + " %3d%% (%8zd/%8zd), time: %10.0f + %5ds, xwin: %#x\n" + " src=[%s]\n" + " dst=[%s]\n", + ere->id, ere->op, status, ere->finished, ere->needs_attention, + ere->percent, ere->done, ere->total, ere->start_time, ere->duration, + e_fm2_op_registry_entry_xwin_get(ere), + ere->src, ere->dst); +} + +static int +_e_fm2_op_registry_entry_add_cb(void *data, int type, void *event) +{ + const E_Fm2_Op_Registry_Entry *ere = event; + printf("E FM OPERATION STARTED: id=%d, op=%d\n", ere->id, ere->op); + return ECORE_CALLBACK_RENEW; +} + +static int +_e_fm2_op_registry_entry_del_cb(void *data, int type, void *event) +{ + const E_Fm2_Op_Registry_Entry *ere = event; + puts("E FM OPERATION FINISHED:"); + _e_fm2_op_registry_entry_print(ere); + puts("---"); + return ECORE_CALLBACK_RENEW; +} + +static int +_e_fm2_op_registry_entry_changed_cb(void *data, int type, void *event) +{ + const E_Fm2_Op_Registry_Entry *ere = event; + puts("E FM OPERATION CHANGED:"); + _e_fm2_op_registry_entry_print(ere); + puts("---"); + return ECORE_CALLBACK_RENEW; +} + +static Ecore_Event_Handler *_e_fm2_op_registry_entry_add_handler = NULL; +static Ecore_Event_Handler *_e_fm2_op_registry_entry_del_handler = NULL; +static Ecore_Event_Handler *_e_fm2_op_registry_entry_changed_handler = NULL; +/////////////// DBG: + /***/ EAPI int @@ -594,6 +693,7 @@ e_fm2_init(void) } // _e_fm2_client_spawn(); e_fm2_custom_file_init(); + e_fm2_op_registry_init(); efreet_mime_init(); /* XXX: move this to a central/global place? */ @@ -606,6 +706,21 @@ e_fm2_init(void) _e_fm2_mime_app_desktop = eina_stringshare_add("application/x-desktop"); _e_fm2_mime_app_edje = eina_stringshare_add("application/x-edje"); + /// DBG + if (!_e_fm2_op_registry_entry_add_handler) + _e_fm2_op_registry_entry_add_handler = + ecore_event_handler_add(E_EVENT_FM_OP_REGISTRY_ADD, + _e_fm2_op_registry_entry_add_cb, NULL); + if (!_e_fm2_op_registry_entry_del_handler) + _e_fm2_op_registry_entry_del_handler = + ecore_event_handler_add(E_EVENT_FM_OP_REGISTRY_DEL, + _e_fm2_op_registry_entry_del_cb, NULL); + if (!_e_fm2_op_registry_entry_changed_handler) + _e_fm2_op_registry_entry_changed_handler = + ecore_event_handler_add(E_EVENT_FM_OP_REGISTRY_CHANGED, + _e_fm2_op_registry_entry_changed_cb, NULL); + /// DBG + return 1; } @@ -618,6 +733,24 @@ e_fm2_shutdown(void) _eina_stringshare_replace(&_e_fm2_mime_app_desktop, NULL); _eina_stringshare_replace(&_e_fm2_mime_app_edje, NULL); + /// DBG + if (_e_fm2_op_registry_entry_add_handler) + { + ecore_event_handler_del(_e_fm2_op_registry_entry_add_handler); + _e_fm2_op_registry_entry_add_handler = NULL; + } + if (_e_fm2_op_registry_entry_del_handler) + { + ecore_event_handler_del(_e_fm2_op_registry_entry_del_handler); + _e_fm2_op_registry_entry_del_handler = NULL; + } + if (_e_fm2_op_registry_entry_changed_handler) + { + ecore_event_handler_del(_e_fm2_op_registry_entry_changed_handler); + _e_fm2_op_registry_entry_changed_handler = NULL; + } + /// DBG + ecore_timer_del(_e_fm2_mime_flush); _e_fm2_mime_flush = NULL; ecore_timer_del(_e_fm2_mime_clear); @@ -628,6 +761,7 @@ e_fm2_shutdown(void) E_FREE(_e_fm2_meta_path); e_fm2_custom_file_shutdown(); _e_storage_volume_edd_shutdown(); + e_fm2_op_registry_shutdown(); efreet_mime_shutdown(); ecore_job_shutdown(); eina_stringshare_shutdown(); @@ -2247,22 +2381,26 @@ _e_fm2_client_monitor_del(int id, const char *path) } static int -_e_fm_client_file_del(const char *files) +_e_fm_client_file_del(const char *files, Evas_Object *e_fm) { - return _e_fm_client_send_new(E_FM_OP_REMOVE, (void *)files, strlen(files) + 1); + int id = _e_fm_client_send_new(E_FM_OP_REMOVE, (void *)files, strlen(files) + 1); + e_fm2_op_registry_entry_add(id, e_fm, E_FM_OP_REMOVE); + return id; } static int -_e_fm2_client_file_trash(const char *path) +_e_fm2_client_file_trash(const char *path, Evas_Object *e_fm) { - return _e_fm_client_send_new(E_FM_OP_TRASH, (void *)path, strlen(path) + 1); + int id = _e_fm_client_send_new(E_FM_OP_TRASH, (void *)path, strlen(path) + 1); + e_fm2_op_registry_entry_add(id, e_fm, E_FM_OP_TRASH); + return id; } static int -_e_fm2_client_file_mkdir(const char *path, const char *rel, int rel_to, int x, int y, int res_w, int res_h) +_e_fm2_client_file_mkdir(const char *path, const char *rel, int rel_to, int x, int y, int res_w, int res_h, Evas_Object *e_fm) { char *d; - int l1, l2, l; + int l1, l2, l, id; l1 = strlen(path); l2 = strlen(rel); @@ -2274,21 +2412,26 @@ _e_fm2_client_file_mkdir(const char *path, const char *rel, int rel_to, int x, i memcpy(d + l1 + 1 + l2 + 1 + sizeof(int), &x, sizeof(int)); memcpy(d + l1 + 1 + l2 + 1 + (2 * sizeof(int)), &y, sizeof(int)); - return _e_fm_client_send_new(E_FM_OP_MKDIR, (void *)d, l); + id = _e_fm_client_send_new(E_FM_OP_MKDIR, (void *)d, l); + e_fm2_op_registry_entry_add(id, e_fm, E_FM_OP_MKDIR); + return id; } static int -_e_fm_client_file_move(const char *args) +_e_fm_client_file_move(const char *args, Evas_Object *e_fm) { - return _e_fm_client_send_new(E_FM_OP_MOVE, (void *)args, strlen(args) + 1); + int id = _e_fm_client_send_new(E_FM_OP_MOVE, (void *)args, strlen(args) + 1); + printf("REQUEST CLIENT TO MOVE: %s, id=%d, op=%d\n", args, id, E_FM_OP_MOVE); + e_fm2_op_registry_entry_add(id, e_fm, E_FM_OP_MOVE); + return id; } static int -_e_fm2_client_file_symlink(const char *path, const char *dest, const char *rel, int rel_to, int x, int y, int res_w, int res_h) +_e_fm2_client_file_symlink(const char *path, const char *dest, const char *rel, int rel_to, int x, int y, int res_w, int res_h, Evas_Object *e_fm) { #if 0 char *d; - int l1, l2, l3, l; + int l1, l2, l3, l, id; l1 = strlen(path); l2 = strlen(dest); @@ -2321,7 +2464,9 @@ _e_fm2_client_file_symlink(const char *path, const char *dest, const char *rel, e_fm2_custom_file_flush(); } - return _e_fm_client_send_new(E_FM_OP_SYMLINK, (void *)d, l); + id = _e_fm_client_send_new(E_FM_OP_SYMLINK, (void *)d, l); + e_fm2_op_registry_entry_add(id, e_fm, E_FM_OP_SYMLINK); + return id; #else char *args = NULL; size_t size = 0, length = 0; @@ -2331,22 +2476,27 @@ _e_fm2_client_file_symlink(const char *path, const char *dest, const char *rel, args = _e_fm_string_append_quoted(args, &size, &length, dest); fputs("WARNING: using new E_FM_OP_SYMLINK, remove deprecated ASAP\n", stderr); - int r = _e_fm_client_file_symlink(args); + int r = _e_fm_client_file_symlink(args, e_fm); free(args); return r; #endif } static int -_e_fm_client_file_copy(const char *args) +_e_fm_client_file_copy(const char *args, Evas_Object *e_fm) { - return _e_fm_client_send_new(E_FM_OP_COPY, (void *)args, strlen(args) + 1); + int id = _e_fm_client_send_new(E_FM_OP_COPY, (void *)args, strlen(args) + 1); + printf("REQUEST CLIENT TO COPY: %s, id=%d, op=%d\n", args, id, E_FM_OP_COPY); + e_fm2_op_registry_entry_add(id, e_fm, E_FM_OP_COPY); + return id; } static int -_e_fm_client_file_symlink(const char *args) +_e_fm_client_file_symlink(const char *args, Evas_Object *e_fm) { - return _e_fm_client_send_new(E_FM_OP_SYMLINK, (void *)args, strlen(args) + 1); + int id = _e_fm_client_send_new(E_FM_OP_SYMLINK, (void *)args, strlen(args) + 1); + e_fm2_op_registry_entry_add(id, e_fm, E_FM_OP_SYMLINK); + return id; } EAPI int @@ -2753,18 +2903,21 @@ e_fm2_client_data(Ecore_Ipc_Event_Client_Data *e) break; case E_FM_OP_ERROR:/*error*/ - printf("%s:%s(%d) Error from slave #%d: %s\n", __FILE__, __FUNCTION__, __LINE__, e->ref, (char *)e->data); - _e_fm_error_dialog(e->ref, e->data); + printf("%s:%s(%d) Error from slave #%d: %s\n", __FILE__, __FUNCTION__, __LINE__, e->ref, (char *)e->data); + _e_fm_error_dialog(e->ref, e->data); + _e_fm2_op_registry_error(e->ref); break; case E_FM_OP_ERROR_RETRY_ABORT:/*error*/ - printf("%s:%s(%d) Error from slave #%d: %s\n", __FILE__, __FUNCTION__, __LINE__, e->ref, (char *)e->data); - _e_fm_retry_abort_dialog(e->ref, (char *)e->data); + printf("%s:%s(%d) Error from slave #%d: %s\n", __FILE__, __FUNCTION__, __LINE__, e->ref, (char *)e->data); + _e_fm_retry_abort_dialog(e->ref, (char *)e->data); + _e_fm2_op_registry_error(e->ref); break; case E_FM_OP_OVERWRITE:/*overwrite*/ - printf("%s:%s(%d) Overwrite from slave #%d: %s\n", __FILE__, __FUNCTION__, __LINE__, e->ref, (char *)e->data); - _e_fm_overwrite_dialog(e->ref, (char *)e->data); + printf("%s:%s(%d) Overwrite from slave #%d: %s\n", __FILE__, __FUNCTION__, __LINE__, e->ref, (char *)e->data); + _e_fm_overwrite_dialog(e->ref, (char *)e->data); + _e_fm2_op_registry_needs_attention(e->ref); break; case E_FM_OP_PROGRESS:/*progress*/ @@ -2785,10 +2938,28 @@ e_fm2_client_data(Ecore_Ipc_Event_Client_Data *e) #undef UP src = p; dst = p + strlen(src) + 1; - printf("%s:%s(%d) Progress from slave #%d:\n\t%d%% done,\n\t%d seconds left,\n\t%d done,\n\t%d total,\n\tsrc = %s,\n\tdst = %s.\n", __FILE__, __FUNCTION__, __LINE__, e->ref, percent, seconds, done, total, src, dst); + // printf("%s:%s(%d) Progress from slave #%d:\n\t%d%% done,\n\t%d seconds left,\n\t%zd done,\n\t%zd total,\n\tsrc = %s,\n\tdst = %s.\n", __FILE__, __FUNCTION__, __LINE__, e->ref, percent, seconds, done, total, src, dst); + + E_Fm2_Op_Registry_Entry *ere = e_fm2_op_registry_entry_get(e->ref); + if (!ere) return; + ere->percent = percent; + ere->done = done; + ere->total = total; + ere->duration = seconds; + e_fm2_op_registry_entry_files_set(ere, src, dst); + if (ere->percent == 100) + { + ere->status = E_FM2_OP_STATUS_SUCCESSFUL; + ere->finished = 1; + } + e_fm2_op_registry_entry_changed(ere); } break; + case E_FM_OP_QUIT:/*finished*/ + e_fm2_op_registry_entry_del(e->ref); + break; + default: break; } @@ -3066,6 +3237,7 @@ _e_fm2_buffer_fill(Evas_Object *obj) int bufused, buffree; const char *realpath; const E_Fm2_Icon_Info *ici; + Eina_Bool ret; sel = e_fm2_selected_list_get(obj); if (!sel) return 0; @@ -3085,6 +3257,7 @@ _e_fm2_buffer_fill(Evas_Object *obj) pfile = buf + bufused; buffree = sizeof(buf) - bufused; + ret = !!sel; EINA_LIST_FREE(sel, ici) { if (!ici) continue; @@ -3092,7 +3265,7 @@ _e_fm2_buffer_fill(Evas_Object *obj) _e_fm_file_buffer = eina_list_append(_e_fm_file_buffer, _e_fm2_uri_escape(buf)); } - return !!sel; + return ret; } static void @@ -3152,11 +3325,11 @@ _e_fm2_file_paste(Evas_Object *obj) /* Roll the operation! */ if (_e_fm_file_buffer_copying) { - _e_fm_client_file_copy(args); + _e_fm_client_file_copy(args, sd->obj); } else { - _e_fm_client_file_move(args); + _e_fm_client_file_move(args, sd->obj); } free(args); @@ -3204,7 +3377,7 @@ _e_fm2_file_symlink(Evas_Object *obj) /* Roll the operation! */ if (_e_fm_file_buffer_copying) - _e_fm_client_file_symlink(args); + _e_fm_client_file_symlink(args, sd->obj); free(args); } @@ -5652,55 +5825,54 @@ _e_fm_icon_save_position(const char *file, Evas_Coord x, Evas_Coord y, Evas_Coor e_fm2_custom_file_flush(); } +struct e_fm_drop_menu_data +{ + Evas_Object *e_fm; + char *args; +}; + static void _e_fm_drop_menu_copy_cb(void *data, E_Menu *m, E_Menu_Item *mi) { - char *args = data; - - if (!data) return; - - _e_fm_client_file_copy(args); + struct e_fm_drop_menu_data *d = data; + if (!d) return; + _e_fm_client_file_copy(d->args, d->e_fm); } static void _e_fm_drop_menu_move_cb(void *data, E_Menu *m, E_Menu_Item *mi) { - char *args = data; - - if (!data) return; - - _e_fm_client_file_move(args); + struct e_fm_drop_menu_data *d = data; + if (!d) return; + _e_fm_client_file_move(d->args, d->e_fm); } static void _e_fm_drop_menu_symlink_cb(void *data, E_Menu *m, E_Menu_Item *mi) { - char *args = data; - - if (!data) return; - - _e_fm_client_file_symlink(args); + struct e_fm_drop_menu_data *d = data; + if (!d) return; + _e_fm_client_file_symlink(d->args, d->e_fm); } static void _e_fm_drop_menu_abort_cb(void *data, E_Menu *m, E_Menu_Item *mi) { - if (!data) return; } static void -_e_fm_drop_menu_post_cb(void *data, E_Menu *m) +_e_fm_drop_menu_free(void *data) { - char *args = data; - - if (!data) return; - - free(args); + struct e_fm_drop_menu_data *d = e_object_data_get(data); + if (!d) return; + free(d->args); + free(d); } static void -_e_fm_drop_menu(char *args) +_e_fm_drop_menu(char *args, Evas_Object *e_fm) { + struct e_fm_drop_menu_data *d; E_Menu *menu = e_menu_new(); E_Menu_Item *item = NULL; E_Manager *man = NULL; @@ -5710,14 +5882,27 @@ _e_fm_drop_menu(char *args) if (!menu) return; + d = malloc(sizeof(*d)); + if (!d) + { + e_object_del(E_OBJECT(menu)); + return; + } + + d->e_fm = e_fm; + d->args = args; + + e_object_data_set(E_OBJECT(menu), d); + e_object_free_attach_func_set(E_OBJECT(menu), _e_fm_drop_menu_free); + item = e_menu_item_new(menu); e_menu_item_label_set(item, _("Copy")); - e_menu_item_callback_set(item, _e_fm_drop_menu_copy_cb, args); + e_menu_item_callback_set(item, _e_fm_drop_menu_copy_cb, d); e_util_menu_item_theme_icon_set(item, "edit-copy"); item = e_menu_item_new(menu); e_menu_item_label_set(item, _("Move")); - e_menu_item_callback_set(item, _e_fm_drop_menu_move_cb, args); + e_menu_item_callback_set(item, _e_fm_drop_menu_move_cb, d); e_menu_item_icon_edje_set(item, e_theme_edje_file_get("base/theme/fileman", "e/fileman/default/button/move"), @@ -5725,7 +5910,7 @@ _e_fm_drop_menu(char *args) item = e_menu_item_new(menu); e_menu_item_label_set(item, _("Link")); - e_menu_item_callback_set(item, _e_fm_drop_menu_symlink_cb, args); + e_menu_item_callback_set(item, _e_fm_drop_menu_symlink_cb, d); e_util_menu_item_theme_icon_set(item, "emblem-symbolic-link"); item = e_menu_item_new(menu); @@ -5733,35 +5918,23 @@ _e_fm_drop_menu(char *args) item = e_menu_item_new(menu); e_menu_item_label_set(item, _("Abort")); - e_menu_item_callback_set(item, _e_fm_drop_menu_abort_cb, args); + e_menu_item_callback_set(item, _e_fm_drop_menu_abort_cb, d); e_menu_item_icon_edje_set(item, e_theme_edje_file_get("base/theme/fileman", "e/fileman/default/button/abort"), "e/fileman/default/button/abort"); man = e_manager_current_get(); - if (!man) - { - e_object_del(E_OBJECT(menu)); - return; - } + if (!man) goto error; con = e_container_current_get(man); - if (!con) - { - e_object_del(E_OBJECT(menu)); - return; - } + if (!con) goto error; ecore_x_pointer_xy_get(con->win, &x, &y); zone = e_util_zone_current_get(man); - if (!zone) - { - e_object_del(E_OBJECT(menu)); - return; - } - e_menu_post_deactivate_callback_set(menu, _e_fm_drop_menu_post_cb, args); - e_menu_activate_mouse(menu, zone, - x, y, 1, 1, - E_MENU_POP_DIRECTION_DOWN, 0); + if (!zone) goto error; + e_menu_activate_mouse(menu, zone, x, y, 1, 1, E_MENU_POP_DIRECTION_DOWN, 0); + + error: + e_object_del(E_OBJECT(menu)); } static void @@ -5906,7 +6079,7 @@ _e_fm2_cb_dnd_drop(void *data, const char *type, void *event) sd->realpath, ecore_file_file_get(fp)); if (sd->config->view.link_drop) { - _e_fm2_client_file_symlink(buf, fp, sd->drop_icon->info.file, sd->drop_after, -9999, -9999, sd->h, sd->h); + _e_fm2_client_file_symlink(buf, fp, sd->drop_icon->info.file, sd->drop_after, -9999, -9999, sd->h, sd->h, sd->obj); } else { @@ -5941,17 +6114,17 @@ _e_fm2_cb_dnd_drop(void *data, const char *type, void *event) if (e_drop_handler_action_get() == ECORE_X_ATOM_XDND_ACTION_COPY) { - _e_fm_client_file_copy(args); + _e_fm_client_file_copy(args, sd->obj); free(args); } else if (e_drop_handler_action_get() == ECORE_X_ATOM_XDND_ACTION_MOVE) { - _e_fm_client_file_move(args); + _e_fm_client_file_move(args, sd->obj); free(args); } else if (e_drop_handler_action_get() == ECORE_X_ATOM_XDND_ACTION_ASK) { - _e_fm_drop_menu(args); + _e_fm_drop_menu(args, sd->obj); } _e_fm2_dnd_drop_hide(sd->obj); @@ -6202,7 +6375,7 @@ _e_fm2_cb_drag_finished(E_Drag *drag, int dropped) free(drag->data); } -void +static void _e_fm_drag_key_down_cb(E_Drag *drag, Ecore_Event_Key *e) { if (!strncmp(e->keyname, "Alt", 3)) @@ -6222,7 +6395,7 @@ _e_fm_drag_key_down_cb(E_Drag *drag, Ecore_Event_Key *e) } } -void +static void _e_fm_drag_key_up_cb(E_Drag *drag, Ecore_Event_Key *e) { /* Default action would be move. ;) */ @@ -8139,7 +8312,7 @@ _e_fm2_new_directory_yes_cb(char *text, void *data) { snprintf(buf, sizeof(buf), "%s/%s", sd->realpath, text); - _e_fm2_client_file_mkdir(buf, "", 0, 0, 0, sd->w, sd->h); + _e_fm2_client_file_mkdir(buf, "", 0, 0, 0, sd->w, sd->h, sd->obj); } } @@ -8210,7 +8383,7 @@ _e_fm2_file_rename_yes_cb(char *text, void *data) args = _e_fm_string_append_char(args, &size, &length, ' '); args = _e_fm_string_append_quoted(args, &size, &length, newpath); - _e_fm_client_file_move(args); + _e_fm_client_file_move(args, ic->sd->obj); free(args); } } @@ -8267,6 +8440,7 @@ static void _e_fm_retry_abort_delete_cb(void *obj) static void _e_fm_retry_abort_retry_cb(void *data, E_Dialog *dialog) { int *id = E_OBJECT(dialog)->data; + _e_fm2_op_registry_go_on(*id); _e_fm_client_send(E_FM_OP_ERROR_RESPONSE_RETRY, *id, NULL, 0); e_object_del(E_OBJECT(dialog)); } @@ -8274,6 +8448,7 @@ static void _e_fm_retry_abort_retry_cb(void *data, E_Dialog *dialog) static void _e_fm_retry_abort_abort_cb(void *data, E_Dialog *dialog) { int *id = E_OBJECT(dialog)->data; + _e_fm2_op_registry_aborted(*id); _e_fm_client_send(E_FM_OP_ERROR_RESPONSE_ABORT, *id, NULL, 0); e_object_del(E_OBJECT(dialog)); } @@ -8325,6 +8500,7 @@ static void _e_fm_overwrite_no_cb(void *data, E_Dialog *dialog) { int *id = E_OBJECT(dialog)->data; + _e_fm2_op_registry_go_on(*id); _e_fm_client_send(E_FM_OP_OVERWRITE_RESPONSE_NO, *id, NULL, 0); e_object_del(E_OBJECT(dialog)); } @@ -8333,6 +8509,7 @@ static void _e_fm_overwrite_no_all_cb(void *data, E_Dialog *dialog) { int *id = E_OBJECT(dialog)->data; + _e_fm2_op_registry_go_on(*id); _e_fm_client_send(E_FM_OP_OVERWRITE_RESPONSE_NO_ALL, *id, NULL, 0); e_object_del(E_OBJECT(dialog)); } @@ -8341,6 +8518,7 @@ static void _e_fm_overwrite_yes_cb(void *data, E_Dialog *dialog) { int *id = E_OBJECT(dialog)->data; + _e_fm2_op_registry_go_on(*id); _e_fm_client_send(E_FM_OP_OVERWRITE_RESPONSE_YES, *id, NULL, 0); e_object_del(E_OBJECT(dialog)); } @@ -8349,6 +8527,7 @@ static void _e_fm_overwrite_yes_all_cb(void *data, E_Dialog *dialog) { int *id = E_OBJECT(dialog)->data; + _e_fm2_op_registry_go_on(*id); _e_fm_client_send(E_FM_OP_OVERWRITE_RESPONSE_YES_ALL, *id, NULL, 0); e_object_del(E_OBJECT(dialog)); } @@ -8401,6 +8580,7 @@ static void _e_fm_error_retry_cb(void *data, E_Dialog *dialog) { int *id = E_OBJECT(dialog)->data; + _e_fm2_op_registry_go_on(*id); _e_fm_client_send(E_FM_OP_ERROR_RESPONSE_RETRY, *id, NULL, 0); e_object_del(E_OBJECT(dialog)); } @@ -8409,6 +8589,7 @@ static void _e_fm_error_abort_cb(void *data, E_Dialog *dialog) { int *id = E_OBJECT(dialog)->data; + _e_fm2_op_registry_aborted(*id); _e_fm_client_send(E_FM_OP_ERROR_RESPONSE_ABORT, *id, NULL, 0); e_object_del(E_OBJECT(dialog)); } @@ -8417,6 +8598,7 @@ static void _e_fm_error_ignore_this_cb(void *data, E_Dialog *dialog) { int *id = E_OBJECT(dialog)->data; + _e_fm2_op_registry_go_on(*id); _e_fm_client_send(E_FM_OP_ERROR_RESPONSE_IGNORE_THIS, *id, NULL, 0); e_object_del(E_OBJECT(dialog)); } @@ -8425,6 +8607,7 @@ static void _e_fm_error_ignore_all_cb(void *data, E_Dialog *dialog) { int *id = E_OBJECT(dialog)->data; + _e_fm2_op_registry_go_on(*id); _e_fm_client_send(E_FM_OP_ERROR_RESPONSE_IGNORE_ALL, *id, NULL, 0); e_object_del(E_OBJECT(dialog)); } @@ -8607,7 +8790,7 @@ _e_fm2_file_delete_yes_cb(void *data, E_Dialog *dialog) files = _e_fm_string_append_quoted(files, &size, &len, buf); } - _e_fm_client_file_del(files); + _e_fm_client_file_del(files, ic->sd->obj); free(files); diff --git a/src/bin/e_fm_main.c b/src/bin/e_fm_main.c index 18c8072be..158d69b52 100644 --- a/src/bin/e_fm_main.c +++ b/src/bin/e_fm_main.c @@ -1605,6 +1605,7 @@ static int _e_fm_slave_del_cb(void *data, int type, void *event) if (!e) return 1; slave = ecore_exe_data_get(e->exe); + _e_client_send(slave->id, E_FM_OP_QUIT, NULL, 0); if (!slave) return 1; diff --git a/src/bin/e_fm_op.c b/src/bin/e_fm_op.c index f3f0ee8e6..491af7bbe 100644 --- a/src/bin/e_fm_op.c +++ b/src/bin/e_fm_op.c @@ -53,6 +53,7 @@ static int _e_fm_op_scan_idler(void *data); static void _e_fm_op_send_error(E_Fm_Op_Task * task, E_Fm_Op_Type type, const char *fmt, ...); static void _e_fm_op_rollback(E_Fm_Op_Task * task); +static void _e_fm_op_update_progress_report_simple_done(const char *src, const char *dst); static void _e_fm_op_update_progress(E_Fm_Op_Task *task, long long _plus_e_fm_op_done, long long _plus_e_fm_op_total); static void _e_fm_op_copy_stat_info(E_Fm_Op_Task *task); static int _e_fm_op_handle_overwrite(E_Fm_Op_Task *task); @@ -191,10 +192,18 @@ main(int argc, char **argv) if ((type == E_FM_OP_MOVE) && (rename(task->src.name, task->dst.name) == 0)) - _e_fm_op_task_free(task); + { + _e_fm_op_update_progress_report_simple_done + (task->src.name, task->dst.name); + _e_fm_op_task_free(task); + } else if ((type == E_FM_OP_SYMLINK) && (symlink(task->src.name, task->dst.name) == 0)) - _e_fm_op_task_free(task); + { + _e_fm_op_update_progress_report_simple_done + (task->src.name, task->dst.name); + _e_fm_op_task_free(task); + } else _e_fm_op_scan_queue = eina_list_append(_e_fm_op_scan_queue, task); @@ -219,10 +228,16 @@ main(int argc, char **argv) /* Try a rename */ if ((type == E_FM_OP_MOVE) && (rename(argv[2], argv[3]) == 0)) - goto quit; + { + _e_fm_op_update_progress_report_simple_done(argv[2], argv[3]); + goto quit; + } else if ((type == E_FM_OP_SYMLINK) && (symlink(argv[2], argv[3]) == 0)) - goto quit; + { + _e_fm_op_update_progress_report_simple_done(argv[2], argv[3]); + goto quit; + } /* If that doesn't work, setup a copy and delete operation. It's not atomic, but it's the best we can do. */ @@ -847,6 +862,53 @@ _e_fm_op_rollback(E_Fm_Op_Task *task) _e_fm_op_update_progress(task, -REMOVECHUNKSIZE, -REMOVECHUNKSIZE); } +static void +_e_fm_op_update_progress_report(int percent, int eta, double elapsed, size_t done, size_t total, const char *src, const char *dst) +{ + const int magic = E_FM_OP_MAGIC; + const int id = E_FM_OP_PROGRESS; + void *p, *data; + int size, src_len, dst_len; + + src_len = strlen(src); + dst_len = strlen(dst); + + size = 2 * sizeof(int) + 2 * sizeof(size_t) + src_len + 1 + dst_len + 1; + data = alloca(3 * sizeof(int) + size); + if (!data) return; + p = data; + +#define P(value) memcpy(p, &(value), sizeof(int)); p += sizeof(int) + P(magic); + P(id); + P(size); + P(percent); + P(eta); +#undef P + +#define P(value) memcpy(p, &(value), sizeof(size_t)); p += sizeof(size_t) + P(done); + P(total); +#undef P + +#define P(value) memcpy(p, value, value ## _len + 1); p += value ## _len + 1 + P(src); + P(dst); +#undef P + + write(STDOUT_FILENO, data, 3 * sizeof(int) + size); + + E_FM_OP_DEBUG("Time left: %d at %e\n", eta, elapsed); + E_FM_OP_DEBUG("Progress %d. \n", percent); +} + +static void +_e_fm_op_update_progress_report_simple_done(const char *src, const char *dst) +{ + _e_fm_op_update_progress_report + (100, 0, 0, REMOVECHUNKSIZE, REMOVECHUNKSIZE, src, dst); +} + /* Updates progress. * _plus_data is how much more works is done and _plus_e_fm_op_total * is how much more work we found out needs to be done @@ -866,11 +928,6 @@ _e_fm_op_update_progress(E_Fm_Op_Task *task, long long _plus_e_fm_op_done, long double eta = 0; static int peta = -1; static E_Fm_Op_Task *ptask = NULL; - void *data; - void *p; - int magic = E_FM_OP_MAGIC; - int id = E_FM_OP_PROGRESS; - int size = 0; _e_fm_op_done += _plus_e_fm_op_done; _e_fm_op_total += _plus_e_fm_op_total; @@ -902,37 +959,9 @@ _e_fm_op_update_progress(E_Fm_Op_Task *task, long long _plus_e_fm_op_done, long ppercent = percent; peta = eta; ptask = task; - - size = 2 * sizeof(int) + 2 * sizeof(size_t) + strlen(ptask->src.name) + 1 + strlen(ptask->dst.name) + 1; - data = malloc(3 * sizeof(int) + size); - - if (!data) return; - p = data; - -#define P(value) memcpy(p, &(value), sizeof(int)); p += sizeof(int) - P(magic); - P(id); - P(size); - P(ppercent); - P(peta); -#undef P - -#define P(value) memcpy(p, &(value), sizeof(size_t)); p += sizeof(size_t) - P(ptask->dst.done); - P(ptask->src.st.st_size); -#undef P - -#define P(value) memcpy(p, value, strlen(value) + 1); p += strlen(value) + 1 - P(ptask->src.name); - P(ptask->dst.name); -#undef P - - write(STDOUT_FILENO, data, 3 * sizeof(int) + size); - - E_FM_OP_DEBUG("Time left: %d at %e\n", peta, ctime - stime); - E_FM_OP_DEBUG("Progress %d. \n", percent); - - free(data); + _e_fm_op_update_progress_report(percent, eta, ctime - stime, + task->dst.done, task->src.st.st_size, + task->src.name, task->dst.name); } } } diff --git a/src/bin/e_fm_op_registry.c b/src/bin/e_fm_op_registry.c new file mode 100644 index 000000000..4268449e6 --- /dev/null +++ b/src/bin/e_fm_op_registry.c @@ -0,0 +1,498 @@ +/* + * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 + */ +#include "e.h" + +EAPI int E_EVENT_FM_OP_REGISTRY_ADD = 0; +EAPI int E_EVENT_FM_OP_REGISTRY_DEL = 0; +EAPI int E_EVENT_FM_OP_REGISTRY_CHANGED = 0; + +static Eina_Hash *_e_fm2_op_registry = NULL; +static unsigned int _e_fm2_init_count = 0; + +typedef struct _E_Fm2_Op_Registry_Entry_Listener E_Fm2_Op_Registry_Entry_Listener; +typedef struct _E_Fm2_Op_Registry_Entry_Internal E_Fm2_Op_Registry_Entry_Internal; + +struct _E_Fm2_Op_Registry_Entry_Listener +{ + EINA_INLIST; + void (*cb)(void *data, const E_Fm2_Op_Registry_Entry *entry); + void *data; + void (*free_data)(void *data); +}; + +struct _E_Fm2_Op_Registry_Entry_Internal +{ + E_Fm2_Op_Registry_Entry entry; + Eina_Inlist *listeners; + int references; + Ecore_Event *changed_event; +}; + +static void +_e_fm2_op_registry_entry_e_fm_deleted(void *data, Evas *evas, Evas_Object *e_fm, void *event) +{ + E_Fm2_Op_Registry_Entry *entry = data; + + entry->e_fm = NULL; + e_fm2_op_registry_entry_changed(entry); +} + +static void +_e_fm2_op_registry_entry_e_fm_monitor_start(const E_Fm2_Op_Registry_Entry *entry) +{ + if (!entry->e_fm) return; + evas_object_event_callback_add + (entry->e_fm, EVAS_CALLBACK_DEL, + _e_fm2_op_registry_entry_e_fm_deleted, entry); +} + +static void +_e_fm2_op_registry_entry_e_fm_monitor_stop(const E_Fm2_Op_Registry_Entry *entry) +{ + if (!entry->e_fm) return; + evas_object_event_callback_del_full + (entry->e_fm, EVAS_CALLBACK_DEL, + _e_fm2_op_registry_entry_e_fm_deleted, entry); +} + + +static inline E_Fm2_Op_Registry_Entry_Internal * +_e_fm2_op_registry_entry_internal_get(const E_Fm2_Op_Registry_Entry *entry) +{ + return (E_Fm2_Op_Registry_Entry_Internal *)entry; +} + +static void +_e_fm2_op_registry_entry_internal_free(E_Fm2_Op_Registry_Entry_Internal *e) +{ + _e_fm2_op_registry_entry_e_fm_monitor_stop(&(e->entry)); + + while (e->listeners) + { + E_Fm2_Op_Registry_Entry_Listener *listener = (void *)e->listeners; + e->listeners = eina_inlist_remove(e->listeners, e->listeners); + + if (listener->free_data) listener->free_data(listener->data); + free(listener); + } + + eina_stringshare_del(e->entry.src); + eina_stringshare_del(e->entry.dst); + free(e); +} + +static inline int +_e_fm2_op_registry_entry_internal_unref(E_Fm2_Op_Registry_Entry_Internal *e) +{ + if (e->references < 1) + return 0; + + e->references--; + if (e->references > 0) + return e->references; + + _e_fm2_op_registry_entry_internal_free(e); + return 0; +} + +static inline int +_e_fm2_op_registry_entry_internal_ref(E_Fm2_Op_Registry_Entry_Internal *e) +{ + e->references++; + return e->references; +} + +static void +_e_fm2_op_registry_entry_listeners_call(const E_Fm2_Op_Registry_Entry_Internal *e) +{ + E_Fm2_Op_Registry_Entry_Listener *l, **shadow; + const E_Fm2_Op_Registry_Entry *entry; + unsigned int i, count; + + /* NB: iterate on a copy in order to allow listeners to be deleted + * from callbacks. number of listeners should be small, so the + * following should do fine. + */ + count = eina_inlist_count(e->listeners); + if (count < 1) return; + + shadow = alloca(sizeof(*shadow) * count); + if (!shadow) return; + + i = 0; + EINA_INLIST_FOREACH(e->listeners, l) + shadow[i++] = l; + + entry = &(e->entry); + for (i = 0; i < count; i++) + shadow[i]->cb(shadow[i]->data, entry); +} + +static void +_e_fm2_op_registry_entry_internal_unref_on_event(void *data, void *event __UNUSED__) +{ + E_Fm2_Op_Registry_Entry_Internal *e = data; + _e_fm2_op_registry_entry_internal_unref(e); +} + +static void +_e_fm2_op_registry_entry_internal_event(E_Fm2_Op_Registry_Entry_Internal *e, int event_type) +{ + _e_fm2_op_registry_entry_internal_ref(e); + ecore_event_add(event_type, &(e->entry), + _e_fm2_op_registry_entry_internal_unref_on_event, e); +} + +Eina_Bool +e_fm2_op_registry_entry_add(int id, Evas_Object *e_fm, E_Fm_Op_Type op) +{ + E_Fm2_Op_Registry_Entry_Internal *e; + + e = E_NEW(E_Fm2_Op_Registry_Entry_Internal, 1); + if (!e) return 0; + + e->entry.id = id; + e->entry.e_fm = e_fm; + e->entry.start_time = ecore_loop_time_get(); + e->entry.op = op; + e->entry.status = E_FM2_OP_STATUS_IN_PROGRESS; + e->references = 1; + + if (!eina_hash_add(_e_fm2_op_registry, &id, e)) + { + free(e); + return 0; + } + + _e_fm2_op_registry_entry_e_fm_monitor_start(&(e->entry)); + _e_fm2_op_registry_entry_internal_event(e, E_EVENT_FM_OP_REGISTRY_ADD); + + return 1; +} + +Eina_Bool +e_fm2_op_registry_entry_del(int id) +{ + E_Fm2_Op_Registry_Entry_Internal *e; + + e = eina_hash_find(_e_fm2_op_registry, &id); + if (!e) return 0; + eina_hash_del_by_key(_e_fm2_op_registry, &id); + + _e_fm2_op_registry_entry_internal_event(e, E_EVENT_FM_OP_REGISTRY_DEL); + _e_fm2_op_registry_entry_internal_unref(e); + + return 1; +} + +static void +_e_fm2_op_registry_entry_internal_unref_on_changed_event(void *data, void *event __UNUSED__) +{ + E_Fm2_Op_Registry_Entry_Internal *e = data; + e->changed_event = NULL; + _e_fm2_op_registry_entry_internal_unref(e); +} + +void +e_fm2_op_registry_entry_changed(const E_Fm2_Op_Registry_Entry *entry) +{ + E_Fm2_Op_Registry_Entry_Internal *e; + + if (!entry) return; + e = _e_fm2_op_registry_entry_internal_get(entry); + + _e_fm2_op_registry_entry_listeners_call(e); + + if (e->changed_event) return; + _e_fm2_op_registry_entry_internal_ref(e); + e->changed_event = ecore_event_add + (E_EVENT_FM_OP_REGISTRY_CHANGED, &(e->entry), + _e_fm2_op_registry_entry_internal_unref_on_changed_event, e); +} + +/** + * Set the new e_fm for this operation. + * + * Use this call instead of directly setting in order to have the + * object to be monitored, when it is gone, the pointer will be made + * NULL. + * + * @note: it will not call any listener or add any event, please use + * e_fm2_op_registry_entry_changed(). + */ +void +e_fm2_op_registry_entry_e_fm_set(E_Fm2_Op_Registry_Entry *entry, Evas_Object *e_fm) +{ + if (!entry) return; + _e_fm2_op_registry_entry_e_fm_monitor_stop(entry); + entry->e_fm = e_fm; + _e_fm2_op_registry_entry_e_fm_monitor_start(entry); +} + +/** + * Set the new files for this operation. + * + * Use this call instead of directly setting in order to have + * stringshare references right. + * + * @note: it will not call any listener or add any event, please use + * e_fm2_op_registry_entry_changed(). + */ +void +e_fm2_op_registry_entry_files_set(E_Fm2_Op_Registry_Entry *entry, const char *src, const char *dst) +{ + if (!entry) return; + + src = eina_stringshare_add(src); + dst = eina_stringshare_add(dst); + + eina_stringshare_del(entry->src); + eina_stringshare_del(entry->dst); + + entry->src = src; + entry->dst = dst; +} + +/** + * Adds a reference to given entry. + * + * @return: new number of references after operation or -1 on error. + */ +EAPI int +e_fm2_op_registry_entry_ref(E_Fm2_Op_Registry_Entry *entry) +{ + E_Fm2_Op_Registry_Entry_Internal *e; + + if (!entry) return -1; + + e = _e_fm2_op_registry_entry_internal_get(entry); + return _e_fm2_op_registry_entry_internal_ref(e); +} + +/** + * Releases a reference to given entry. + * + * @return: new number of references after operation or -1 on error, + * if 0 the entry was freed and pointer is then invalid. + */ +EAPI int +e_fm2_op_registry_entry_unref(E_Fm2_Op_Registry_Entry *entry) +{ + E_Fm2_Op_Registry_Entry_Internal *e; + + if (!entry) return -1; + + e = _e_fm2_op_registry_entry_internal_get(entry); + return _e_fm2_op_registry_entry_internal_unref(e); +} + +/** + * Returns the X window associated to this operation. + * + * This will handle all bureaucracy to get X window based on e_fm evas + * object. + * + * @return: 0 if no window, window identifier otherwise. + */ +EAPI Ecore_X_Window +e_fm2_op_registry_entry_xwin_get(const E_Fm2_Op_Registry_Entry *entry) +{ + Evas *e; + Ecore_Evas *ee; + + if (!entry) return 0; + if (!entry->e_fm) return 0; + + e = evas_object_evas_get(entry->e_fm); + if (!e) return 0; + + ee = evas_data_attach_get(e); + if (!ee) return 0; + + return (Ecore_X_Window)(long)ecore_evas_window_get(ee); +} + +/** + * Discover entry based on its identifier. + * + * @note: does not increment reference. + */ +EAPI E_Fm2_Op_Registry_Entry * +e_fm2_op_registry_entry_get(int id) +{ + return eina_hash_find(_e_fm2_op_registry, &id); +} + +/** + * Adds a function to be called when entry changes. + * + * When entry changes any attribute this function will be called. + * + * @param: entry entry to operate on. + * @param: cb function to callback on changes. + * @param: data extra data to give to @p cb + * @param: free_data function to call when listener is removed, entry + * is deleted or any error occur in this function and listener + * cannot be added. + * + * @note: does not increment reference. + * @note: on errors, @p free_data will be called. + */ +EAPI void +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)) +{ + E_Fm2_Op_Registry_Entry_Internal *e; + E_Fm2_Op_Registry_Entry_Listener *listener; + Eina_Error err; + + if ((!entry) || (!cb)) + { + if (free_data) free_data((void *)data); + return; + } + + listener = malloc(sizeof(*listener)); + if (!listener) + { + if (free_data) free_data((void *)data); + return; + } + listener->cb = cb; + listener->data = (void *)data; + listener->free_data = free_data; + + e = _e_fm2_op_registry_entry_internal_get(entry); + e->listeners = eina_inlist_append(e->listeners, EINA_INLIST_GET(listener)); + err = eina_error_get(); + if (err) + { + EINA_ERROR_PERR("could not add listener: %s\n", + eina_error_msg_get(err)); + + if (free_data) free_data((void *)data); + free(listener); + return; + } +} + +/** + * Removes the function to be called when entry changes. + * + * @param: entry entry to operate on. + * @param: cb function to callback on changes. + * @param: data extra data to give to @p cb + * + * @note: does not decrement reference. + * @see: e_fm2_op_registry_entry_listener_add() + */ +EAPI void +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) +{ + E_Fm2_Op_Registry_Entry_Internal *e; + E_Fm2_Op_Registry_Entry_Listener *l; + + if ((!entry) || (!cb)) return; + e = _e_fm2_op_registry_entry_internal_get(entry); + + EINA_INLIST_FOREACH(e->listeners, l) + if ((l->cb == cb) && (l->data == data)) + { + e->listeners = eina_inlist_remove(e->listeners, EINA_INLIST_GET(l)); + if (l->free_data) l->free_data(l->data); + return; + } +} + +/** + * Returns an iterator over all the entries in the fm operations registry. + * + * @warning: this iterator is just valid until new entries are added + * or removed (usually happens from main loop). This is because + * when system is back to main loop it can report new events and + * operations can be added or removed from this registry. In other + * words, it is fine to call this function, immediately walk the + * iterator and do something, then free the iterator. You can use + * it to create a shadow list if you wish. + * + * @see e_fm2_op_registry_get_all() + */ +EAPI Eina_Iterator * +e_fm2_op_registry_iterator_new(void) +{ + return eina_hash_iterator_data_new(_e_fm2_op_registry); +} + +/** + * Returns a shadow list with all entries in the registry. + * + * All entries will have references incremented, so you must free the + * list with e_fm2_op_registry_get_all_free() to free the list and + * release these references. + * + * @note: List is unsorted! + * @note: if you need a simple, immediate walk, use + * e_fm2_op_registry_iterator_new() + */ +EAPI Eina_List * +e_fm2_op_registry_get_all(void) +{ + Eina_List *list; + Eina_Iterator *it; + E_Fm2_Op_Registry_Entry_Internal *e; + + list = NULL; + it = eina_hash_iterator_data_new(_e_fm2_op_registry); + EINA_ITERATOR_FOREACH(it, e) + { + _e_fm2_op_registry_entry_internal_ref(e); + list = eina_list_append(list, &(e->entry)); + } + eina_iterator_free(it); + + return list; +} + +EAPI void +e_fm2_op_registry_get_all_free(Eina_List *list) +{ + E_Fm2_Op_Registry_Entry *entry; + EINA_LIST_FREE(list, entry) + e_fm2_op_registry_entry_unref(entry); +} + +EAPI unsigned int +e_fm2_op_registry_init(void) +{ + _e_fm2_init_count++; + if (_e_fm2_init_count > 1) return _e_fm2_init_count; + + _e_fm2_op_registry = eina_hash_int32_new(NULL); + if (!_e_fm2_op_registry) + { + _e_fm2_init_count = 0; + return 0; + } + + if (E_EVENT_FM_OP_REGISTRY_ADD == 0) + E_EVENT_FM_OP_REGISTRY_ADD = ecore_event_type_new(); + if (E_EVENT_FM_OP_REGISTRY_DEL == 0) + E_EVENT_FM_OP_REGISTRY_DEL = ecore_event_type_new(); + if (E_EVENT_FM_OP_REGISTRY_CHANGED == 0) + E_EVENT_FM_OP_REGISTRY_CHANGED = ecore_event_type_new(); + + return 1; +} + +EAPI unsigned int +e_fm2_op_registry_shutdown(void) +{ + if (_e_fm2_init_count == 0) return 0; + _e_fm2_init_count--; + if (_e_fm2_init_count > 0) return _e_fm2_init_count; + + eina_hash_free(_e_fm2_op_registry); + _e_fm2_op_registry = NULL; + + return 0; +} diff --git a/src/bin/e_fm_op_registry.h b/src/bin/e_fm_op_registry.h new file mode 100644 index 000000000..44de284d0 --- /dev/null +++ b/src/bin/e_fm_op_registry.h @@ -0,0 +1,67 @@ +/* + * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 + */ +#ifdef E_TYPEDEFS + +typedef enum _E_Fm2_Op_Status +{ + E_FM2_OP_STATUS_UNKNOWN = 0, + E_FM2_OP_STATUS_IN_PROGRESS, + E_FM2_OP_STATUS_SUCCESSFUL, + E_FM2_OP_STATUS_ABORTED, + E_FM2_OP_STATUS_ERROR +} E_Fm2_Op_Status; + +typedef struct _E_Fm2_Op_Registry_Entry E_Fm2_Op_Registry_Entry; + +#else +#ifndef E_FM_OP_REGISTRY_H +#define E_FM_OP_REGISTRY_H + +struct _E_Fm2_Op_Registry_Entry +{ + int id; + int percent; /* XXX use char? */ + size_t done; + size_t total; + Evas_Object *e_fm; + const char *src; /* stringshared */ + const char *dst; /* stringshared */ + double start_time; + int duration; /* XXX use double? */ + E_Fm_Op_Type op; + E_Fm2_Op_Status status; + Eina_Bool needs_attention:1; + Eina_Bool finished:1; +}; + +extern EAPI int E_EVENT_FM_OP_REGISTRY_ADD; +extern EAPI int E_EVENT_FM_OP_REGISTRY_DEL; +extern EAPI int E_EVENT_FM_OP_REGISTRY_CHANGED; + +EAPI int e_fm2_op_registry_entry_ref(E_Fm2_Op_Registry_Entry *entry); +EAPI int e_fm2_op_registry_entry_unref(E_Fm2_Op_Registry_Entry *entry); + +EAPI Ecore_X_Window e_fm2_op_registry_entry_xwin_get(const E_Fm2_Op_Registry_Entry *entry); + +EAPI E_Fm2_Op_Registry_Entry *e_fm2_op_registry_entry_get(int id); + +EAPI void 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)); +EAPI void 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); + +EAPI Eina_Iterator *e_fm2_op_registry_iterator_new(void); +EAPI Eina_List *e_fm2_op_registry_get_all(void); +EAPI void e_fm2_op_registry_get_all_free(Eina_List *list); + +EAPI unsigned int e_fm2_op_registry_init(void); +EAPI unsigned int e_fm2_op_registry_shutdown(void); + +/* E internal/private functions, symbols not exported outside e binary (e_fm.c mainly) */ +Eina_Bool e_fm2_op_registry_entry_add(int id, Evas_Object *e_fm, E_Fm_Op_Type op); +Eina_Bool e_fm2_op_registry_entry_del(int id); +void e_fm2_op_registry_entry_changed(const E_Fm2_Op_Registry_Entry *entry); +void e_fm2_op_registry_entry_e_fm_set(E_Fm2_Op_Registry_Entry *entry, Evas_Object *e_fm); +void e_fm2_op_registry_entry_files_set(E_Fm2_Op_Registry_Entry *entry, const char *src, const char *dst); + +#endif +#endif diff --git a/src/bin/e_includes.h b/src/bin/e_includes.h index a34031942..1a399e99f 100644 --- a/src/bin/e_includes.h +++ b/src/bin/e_includes.h @@ -103,6 +103,7 @@ #include "e_int_border_prop.h" #include "e_entry_dialog.h" #include "e_fm.h" +#include "e_fm_op_registry.h" #include "e_widget_scrollframe.h" #include "e_sha1.h" #include "e_widget_framelist.h"