add filemanager operation registry.

This huge commit will add e_fm2_op_registry, a central place that will
store all on-going operations. You will find that it will report when
operations are added, remove and when they change, for example when
they change progress.

Please notice that the recommended way to present information is to
add listener to specific entries, as opposed to use
E_EVENT_FM_OP_REGISTRY_CHANGED since it will be called immediately and
you do not have to filter which entry is being changed.

Entries will be associated with the e_fm object that originated
it. With that one can get the Ecore_X_Window and request the window to
be raised from somewhere else (ie: gadman/gadget). If object is
deleted (ie: window is closed), the pointer will be made NULL and it
will be a "windowless operation".

TO DO (I need someone to do those):

  - e_fwin: windows should present on-going operations as an overlay,
    Dave Andreolli already started such work, it's just a matter of
    using the new infrastructure.

  - create a new gadget that present all on-going operations and maybe
    a history. It would be nice to show the e_fwin of if the entry is
    clicked, as well as a cancel button and a progress bar. See
    "places" module, make them similar.




SVN revision: 39541
devs/princeamd/enlightenment-0.17-elive
Gustavo Sverzut Barbieri 14 years ago
parent 4598a292ed
commit 92cab40cda
  1. 2
      src/bin/Makefile.am
  2. 363
      src/bin/e_fm.c
  3. 1
      src/bin/e_fm_main.c
  4. 109
      src/bin/e_fm_op.c
  5. 498
      src/bin/e_fm_op_registry.c
  6. 67
      src/bin/e_fm_op_registry.h
  7. 1
      src/bin/e_includes.h

@ -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 \

@ -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);

@ -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;

@ -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);
}
}
}

@ -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;
}
}